package com.chukun.spring.bean.lifecycle;

import com.chunkun.ioc.domain.SuperUser;
import com.chunkun.ioc.domain.User;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory;
import org.springframework.util.ObjectUtils;

/**
 * bean实例化前后对bean进行操作 {@link InstantiationAwareBeanPostProcessor}
 * bean 初始化前后，对bean进行操作 {@link BeanPostProcessor }
 *  InstantiationAwareBeanPostProcessor 继承了 BeanPostProcessor接口
 *
 *  所以实现InstantiationAwareBeanPostProcessor 可以完成 bean实例化， 初始化 前后的相关拦截操作
 *
 * @author  chukun
 */
public class BeanLifecycleInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {


    /**
     * bean 实例化前对bean进行拦截，做相关的操作
     * @param beanClass
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if (ObjectUtils.nullSafeEquals("superUser",beanName) && SuperUser.class.equals(beanClass)) {
            // 把配置完成 superUser Bean 覆盖
            return new SuperUser();
        }
        // 保持 Spring IoC 容器的实例化操作
        return null;
    }

    /**
     * bean 实例后的相关拦截操作，
     * 若返回 false bean的增强就会被跳过,
     * @see AbstractAutowireCapableBeanFactory 的 populateBean(String, RootBeanDefinition, BeanWrapper) 的方法 1388行
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if (ObjectUtils.nullSafeEquals("user", beanName) && User.class.equals(bean.getClass())) {
            User user = (User) bean;
            user.setId(2L);
            user.setName("chukun02");
            // "user" 对象不允许属性赋值（填入）（配置元信息 -> 属性值）
            return false;
        }
        return true;
    }

    /**
     * bean 实例化做相关的操作,依赖查找才会调用
     * @param pvs
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        if (ObjectUtils.nullSafeEquals("userHolder",beanName) && UserHolder.class.equals(bean.getClass())){
            final MutablePropertyValues propertyValues;
            if (pvs instanceof MutablePropertyValues) {
                propertyValues = (MutablePropertyValues) pvs;
            } else {
                propertyValues = new MutablePropertyValues();
            }
            propertyValues.addPropertyValue("number","1");
            if (propertyValues.contains("description")) {
                propertyValues.removePropertyValue("description");
                propertyValues.addPropertyValue("description","the userHolder v2");
                System.out.println("postProcessProperties() : The user holder V2");
            }
            return propertyValues;
        }
        return null;
    }

    /**
     * bean 初始化前做相关的拦截,依赖查找才会调用
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (ObjectUtils.nullSafeEquals("userHolder", beanName) && UserHolder.class.equals(bean.getClass())) {
            UserHolder userHolder = (UserHolder) bean;
            // UserHolder description = "The user holder V2"
            userHolder.setDescription("The user holder V3");
            System.out.println("postProcessBeforeInitialization() : The user holder V3");
        }
        return bean;
    }

    /**
     * bean 初始化后做相关的拦截,依赖查找才会调用
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (ObjectUtils.nullSafeEquals("userHolder", beanName) && UserHolder.class.equals(bean.getClass())) {
            UserHolder userHolder = (UserHolder) bean;
            userHolder.setDescription("The user holder V7");
            System.out.println("postProcessAfterInitialization () The user holder V7");
        }
        return bean;
    }
}
